package team.seekers.oj.group.service;

import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import team.seekers.oj.auth.enums.PermissionEnum;
import team.seekers.oj.common.entity.PageResult;
import team.seekers.oj.common.entity.UserSessionDTO;
import team.seekers.oj.common.enums.ApiExceptionEnum;
import team.seekers.oj.common.exception.ApiException;
import team.seekers.oj.common.util.AssertUtils;
import team.seekers.oj.group.converter.GroupConvertUtils;
import team.seekers.oj.group.converter.GroupCreateReqConverter;
import team.seekers.oj.group.converter.GroupListConverter;
import team.seekers.oj.group.converter.GroupManageConverter;
import team.seekers.oj.group.dao.GroupDao;
import team.seekers.oj.group.dao.GroupListDao;
import team.seekers.oj.group.dto.GroupCreateReqDTO;
import team.seekers.oj.group.dto.GroupListDTO;
import team.seekers.oj.group.dto.GroupListReqDTO;
import team.seekers.oj.group.dto.GroupManageDTO;
import team.seekers.oj.group.entity.dao.GroupDO;
import team.seekers.oj.group.entity.dao.GroupDOField;
import team.seekers.oj.group.entity.dao.GroupListDO;
import team.seekers.oj.group.entity.vo.GroupInfoVO;
import team.seekers.oj.group.entity.vo.GroupUserListVO;
import team.seekers.oj.user.service.UserExtensionService;
import team.seekers.oj.user.service.UserManageService;
import team.seekers.oj.user.service.UserService;

import java.util.List;



@Service
public class GroupService {

    @Autowired
    private GroupDao groupDao;

    @Autowired
    private GroupListDao groupListDao;

    @Autowired
    private GroupListConverter groupListConverter;

    @Autowired
    private GroupCreateReqConverter groupCreateReqConverter;

    @Autowired
    private GroupManageConverter groupManageConverter;


    @Autowired
    private UserService userService;

    @Autowired
    private UserManageService userManageService;

    @Autowired
    private UserExtensionService userExtensionService;



    public Long create(GroupCreateReqDTO reqDTO) {
        GroupDO groupDO = groupCreateReqConverter.from(reqDTO);
        AssertUtils.isTrue(groupDao.save(groupDO), ApiExceptionEnum.UNKNOWN_ERROR);
        return groupDO.getId();
    }


    public GroupInfoVO getVO(long groupId) {
        GroupDO contestDO = groupDao.getById(groupId);
        AssertUtils.notNull(contestDO, ApiExceptionEnum.CONTEST_NOT_FOUND);
        GroupInfoVO groupInfoVO = new GroupInfoVO();
        BeanUtils.copyProperties(contestDO,groupInfoVO);
        List<Long> userIds = GroupConvertUtils.groupUsersToUserIdList(contestDO.getUsers());
        List<GroupUserListVO> groupUserListVOS =  userManageService.userIdsToGroupUserList(userIds);
        groupInfoVO.setUsers(groupUserListVOS);
        return groupInfoVO;
    }

    public GroupManageDTO getDTO(long contestId) {
        GroupDO contestDO = groupDao.getById(contestId);
        AssertUtils.notNull(contestDO, ApiExceptionEnum.CONTEST_NOT_FOUND);
        return groupManageConverter.to(contestDO);
    }

    public void update(GroupManageDTO reqDTO) {
        GroupDO groupDO = groupDao.lambdaQuery().select(
                GroupDO::getId,
                GroupDO::getUserId,
                GroupDO::getVersion
        ).eq(GroupDO::getId, reqDTO.getGroupId()).one();
        AssertUtils.notNull(groupDO, ApiExceptionEnum.CONTEST_NOT_FOUND);

        GroupDO groupUpdateDO = groupManageConverter.from(reqDTO);
        groupUpdateDO.setUserNum(groupUpdateDO.getUsers().length / 8);
        groupUpdateDO.setVersion(groupDO.getVersion());
        UpdateWrapper<GroupDO> updater = new UpdateWrapper<>();
        updater.eq(GroupDOField.ID, groupUpdateDO.getId());
        if (!groupDao.update(groupUpdateDO, updater)) {
            throw new ApiException(ApiExceptionEnum.SERVER_BUSY);
        }
    }

    public boolean isGroupManager(Long groupCreatorId, UserSessionDTO userSessionDTO) {
        return PermissionEnum.SUPERADMIN.in(userSessionDTO) ||
                userSessionDTO.userIdEquals(groupCreatorId);
    }

    public void addUser(long groupId, Long userId) {
        // 判断用户是否存在
        AssertUtils.isTrue(userService.queryByUserId(userId) == null,
                ApiExceptionEnum.USER_NOT_FOUND);

        GroupManageDTO query = getDTO(userId);
        GroupManageDTO groupManageDTO = new GroupManageDTO();
        groupManageDTO.setGroupId(groupId);
        query.getUsers().add(userId);
        groupManageDTO.setUsers(query.getUsers());
        update(groupManageDTO);
    }

    public void addUserWithCreate(long groupId, Long userId) {
        // 判断用户是否存在
        if(userService.queryByUserId(userId) == null){

        }
        GroupManageDTO query = getDTO(userId);
        GroupManageDTO groupManageDTO = new GroupManageDTO();
        groupManageDTO.setGroupId(groupId);
        query.getUsers().add(userId);
        groupManageDTO.setUsers(query.getUsers());
        update(groupManageDTO);
    }

    public void removeUser(long groupId, Long userId) {
        GroupManageDTO query = getDTO(userId);
        GroupManageDTO groupManageDTO = new GroupManageDTO();
        groupManageDTO.setGroupId(groupId);
        boolean remove = query.getUsers().remove(userId);
        if(!remove){
            throw new ApiException(ApiExceptionEnum.GROUP_NOT_IN);
        }
        groupManageDTO.setUsers(query.getUsers());
        update(groupManageDTO);
    }

    public List<Long> queryIdToUserIds(Long groupId) {
        GroupDO groupDO = groupDao.lambdaQuery().select(
                GroupDO::getId,
                GroupDO::getVersion,
                GroupDO::getUsers
        ).eq(GroupDO::getId, groupId).one();
        AssertUtils.notNull(groupDO, ApiExceptionEnum.GROUP_NOT_FOUND);
        return GroupConvertUtils.groupUsersToUserIdList(groupDO.getUsers());
    }

    public PageResult<GroupListDTO> page(GroupListReqDTO reqDTO) {
        LambdaQueryChainWrapper<GroupListDO> query = groupListDao.lambdaQuery()
                .orderByDesc(GroupListDO::getGmtModified);
        if (reqDTO.getTeacherId() != null) {
            query.and(o1 -> o1.eq(GroupListDO::getUserId, reqDTO.getTeacherId()));
        }
        if (reqDTO.getStudentId() != null) {
            List<Long> groupIds = userExtensionService.queryParticipateGroup(reqDTO.getStudentId());
            query.and(o1 -> {
                for (Long groupId : groupIds) {
                    o1.or().eq(GroupListDO::getGroupId, groupId);
                }
            });
        }

        Page<GroupListDO> pageResult = query.page(new Page<>(reqDTO.getPageNow(), reqDTO.getPageSize()));
        return new PageResult<>(pageResult.getPages(), groupListConverter.to(pageResult.getRecords()));
    }
}
